// exception.cc 
//	Entry point into the Nachos kernel from user programs.
//	There are two kinds of things that can cause control to
//	transfer back to here from user code:
//
//	syscall -- The user code explicitly requests to call a procedure
//	in the Nachos kernel.  Right now, the only function we support is
//	"Halt".
//
//	exceptions -- The user code does something that the CPU can't handle.
//	For instance, accessing memory that doesn't exist, arithmetic errors,
//	etc.  
//
//	Interrupts (which can also cause control to transfer from user
//	code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "syscall.h"
#include <stdio.h>
#include <iostream>
#include "list.h"


#ifdef NETWORK
#include "network.h"
#include "post.h"
#include "interrupt.h"
#endif

using namespace std;


//this is the maximum length of the name of locks and CV's
#define MAX_NAME_LENGTH   30
//this is the maximum length for printf
#define MAX_CHAR_PRINTF   200
//this is the maximum length of the filename for exec..
#define MAX_PRS_NM_LEN 200

//global varibale to hold the index of the TLB entry to be replaced on page fault exception
int currentTLB = -1;

int copyin(unsigned int vaddr, int len, char *buf) {
	// Copy len bytes from the current thread's virtual address vaddr.
	// Return the number of bytes so read, or -1 if an error occors.
	// Errors can generally mean a bad virtual address was passed in.
	bool result;
	int n=0;			// The number of bytes copied in
	int *paddr = new int;

	while ( n >= 0 && n < len) {
		result = machine->ReadMem( vaddr, 1, paddr );
		while(!result) // FALL 09 CHANGES
		{
			result = machine->ReadMem( vaddr, 1, paddr ); // FALL 09 CHANGES: TO HANDLE PAGE FAULT IN THE ReadMem SYS CALL
		}

		buf[n++] = *paddr;
		if ( !result ) {
			//translation failed
			return -1;
		}
		//if '\0' is encountered return the function
		if(*paddr == '\0') {
			return len;
		}

		vaddr++;
	}

	delete paddr;
	return len;
}

int copyout(unsigned int vaddr, int len, char *buf) {
	// Copy len bytes to the current thread's virtual address vaddr.
	// Return the number of bytes so written, or -1 if an error
	// occors.  Errors can generally mean a bad virtual address was
	// passed in.
	bool result;
	int n=0;			// The number of bytes copied in

	while ( n >= 0 && n < len) {
		// Note that we check every byte's address
		result = machine->WriteMem( vaddr, 1, (int)(buf[n++]) );

		if ( !result ) {
			//translation failed
			return -1;
		}

		vaddr++;
	}

	return n;
}

void Create_Syscall(unsigned int vaddr, int len) {
	// Create the file with the name in the user buffer pointed to by
	// vaddr.  The file name is at most MAXFILENAME chars long.  No
	// way to return errors, though...
	char *buf = new char[len+1];	// Kernel buffer to put the name in

	if (!buf) return;

	if( copyin(vaddr,len,buf) == -1 ) {
		printf("%s","Bad pointer passed to Create\n");
		delete buf;
		return;
	}

	buf[len]='\0';

	fileSystem->Create(buf,0);
	delete[] buf;
	return;
}

int Open_Syscall(unsigned int vaddr, int len) {
	// Open the file with the name in the user buffer pointed to by
	// vaddr.  The file name is at most MAXFILENAME chars long.  If
	// the file is opened successfully, it is put in the address
	// space's file table and an id returned that can find the file
	// later.  If there are any errors, -1 is returned.
	char *buf = new char[len+1];	// Kernel buffer to put the name in
	OpenFile *f;			// The new open file
	int id;				// The openfile id

	if (!buf) {
		printf("%s","Can't allocate kernel buffer in Open\n");
		return -1;
	}

	if( copyin(vaddr,len,buf) == -1 ) {
		printf("%s","Bad pointer passed to Open\n");
		delete[] buf;
		return -1;
	}

	buf[len]='\0';

	f = fileSystem->Open(buf);
	delete[] buf;

	if ( f ) {
		if ((id = currentThread->space->fileTable.Put(f)) == -1 )
			delete f;
		return id;
	}
	else
		return -1;
}

void Write_Syscall(unsigned int vaddr, int len, int id) {
	// Write the buffer to the given disk file.  If ConsoleOutput is
	// the fileID, data goes to the synchronized console instead.  If
	// a Write arrives for the synchronized Console, and no such
	// console exists, create one. For disk files, the file is looked
	// up in the current address space's open file table and used as
	// the target of the write.

	char *buf;		// Kernel buffer for output
	OpenFile *f;	// Open file for output

	if ( id == ConsoleInput) return;

	if ( !(buf = new char[len]) ) {
		printf("%s","Error allocating kernel buffer for write!\n");
		return;
	} else {
		if ( copyin(vaddr,len,buf) == -1 ) {
			printf("%s","Bad pointer passed to to write: data not written\n");
			delete[] buf;
			return;
		}
	}

	if ( id == ConsoleOutput) {
		for (int ii=0; ii<len; ii++) {
			printf("%c",buf[ii]);
		}

	} else {
		if ( (f = (OpenFile *) currentThread->space->fileTable.Get(id)) ) {
			f->Write(buf, len);
		} else {
			printf("%s","Bad OpenFileId passed to Write\n");
			len = -1;
		}
	}

	delete[] buf;
}

int Read_Syscall(unsigned int vaddr, int len, int id) {
	// Write the buffer to the given disk file.  If ConsoleOutput is
	// the fileID, data goes to the synchronized console instead.  If
	// a Write arrives for the synchronized Console, and no such
	// console exists, create one.    We reuse len as the number of bytes
	// read, which is an unnessecary savings of space.
	char *buf;		// Kernel buffer for input
	OpenFile *f;	// Open file for output

	if ( id == ConsoleOutput) return -1;

	if ( !(buf = new char[len]) ) {
		printf("%s","Error allocating kernel buffer in Read\n");
		return -1;
	}

	if ( id == ConsoleInput) {
		//Reading from the keyboard
		scanf("%s", buf);

		if ( copyout(vaddr, len, buf) == -1 ) {
			printf("%s","Bad pointer passed to Read: data not copied\n");
		}
	} else {
		if ( (f = (OpenFile *) currentThread->space->fileTable.Get(id)) ) {
			len = f->Read(buf, len);
			if ( len > 0 ) {
				//Read something from the file. Put into user's address space
				if ( copyout(vaddr, len, buf) == -1 ) {
					printf("%s","Bad pointer passed to Read: data not copied\n");
				}
			}
		} else {
			printf("%s","Bad OpenFileId passed to Read\n");
			len = -1;
		}
	}

	delete[] buf;
	return len;
}

void Close_Syscall(int fd) {
	// Close the file associated with id fd.  No error reporting.
	OpenFile *f = (OpenFile *) currentThread->space->fileTable.Remove(fd);

	if ( f ) {
		delete f;
	} else {
		printf("%s","Tried to close an unopen file\n");
	}
}

/*Create Lock system call*/

int CreateLock_Syscall(unsigned int vaddr, int len)
{
#ifdef NETWORK
	char *buf;
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//Check if length is within range
	if(len<1 || len>MAX_NAME_LENGTH){
		printf("Client CreateLock_Syscall: Illegal lock name length\n");

		delete[] buf;
		return -1;
	}

	buf = new char[len+1];
	if(buf==NULL){
		printf("Client CreateLock_Syscall: Temp buffer cannot be created\n");
		return -1;
	}

	//Check if the passed vaddr is valid
	if(vaddr<0 || (vaddr+len)>=(currentThread->space)->addrSpaceSize){
		printf("Client CreateLock_Syscall: Invalid virtual address passed\n");
		return -1;
	}

	//copy the name of lock from user memory to temp buffer
	if(copyin(vaddr, len, buf)==-1){//bad virtual address if the function returns -1
		printf("Client CreateLock_Syscall: Bad Virtual address\n");
		delete[] buf;
		return -1;
	}
	buf[len]='\0';

	//data to be sent across the network
	char *data = new char[len+6];
	sprintf(data,"%d %s",CreateLock_id, buf);
	DEBUG('p', "Client %d CreateLock_Syscall: \"CreateLock\" request sent to server for lock %s\n",postOffice->netAddr, buf);

	delete[] buf;
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p',"Client %d CreateLock_Syscall: Negative reply from Server. Lock not created\n",postOffice->netAddr);
	}
	else{
		DEBUG('p',"Client %d CreateLock_Syscall: Positive reply from Server. Lock successfully created with id \n",postOffice->netAddr, ret);
	}
	return ret;

#else

	int lockId;
	char *buf;

	//Check if length is within range
	if(len<1 || len>MAX_NAME_LENGTH){
		printf("Process %d Thread %d CreateLock_Syscall: Illegal lock name length\n", \
				currentThread->space->processId, currentThread->threadId);

		delete[] buf;
		return -1;
	}

	buf = new char[len+1];
	if(buf==NULL){
		printf("Process %d Thread %d CreateLock_Syscall: Temp buffer cannot be created\n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	//Check if the passed vaddr is valid
	if(vaddr<0 || (vaddr+len)>=(currentThread->space)->addrSpaceSize){
		printf("Process %d Thread %d CreateLock_Syscall: Invalid virtual address passed\n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	//copy the name of lock from user memory to temp buffer
	if(copyin(vaddr, len, buf)==-1){//bad virtual address if the function returns -1
		printf("Process %d Thread %d CreateLock_Syscall: Bad Virtual address\n", \
				currentThread->space->processId, currentThread->threadId);

		delete[] buf;

		return -1;
	}	
	buf[len]='\0';

	//Check if there is room to create another lock
	kernelLockTableLock->Acquire();
	if((lockId=kernelLockTable.lockBitMap->Find()) == -1){
		printf("Process %d Thread %d CreateLock_Syscall: Number of Locks exceeded limit\n", \
				currentThread->space->processId, currentThread->threadId);
		delete[] buf;
		kernelLockTableLock->Release();
		return -1;
	}


	//Create lock
	kernelLockTable.locks[lockId].lock = new Lock(buf);
	DEBUG('r', "Process %d Thread %d CreateLock_Syscall: Lock Created with id %d and name %s\n", \
			currentThread->space->processId, currentThread->threadId, lockId, kernelLockTable.locks[lockId].lock->getName());

	kernelLockTable.locks[lockId].addrSpace = currentThread->space;
	kernelLockTable.locks[lockId].isDeleted = false;
	kernelLockTable.locks[lockId].isToBeDeleted = false;
	kernelLockTable.locks[lockId].lockCounter = 0;
	kernelLockTableLock->Release();
	//return index of the lock table
	return(lockId);
#endif
}

/*Destroy Lock system call*/
void DestroyLock_Syscall(int lockId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",DestroyLock_id, lockId);
	DEBUG('p', "Client %d DestroyLock_Syscall: \"DestroyLock\" request sent to server for lock id %d\n",postOffice->netAddr, lockId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d DestroyLock_Syscall: Negative Reply from Server. Lock id %d not deleted\n",postOffice->netAddr, lockId);
	}
	else{
		DEBUG('p', "Client %d DestroyLock_Syscall: Positive Reply from Server. Lock id %d successfully deleted\n",postOffice->netAddr, lockId);
	}
	return ;

#else
	//check if lockId is in a valid range
	if(lockId<0 || lockId>=MAX_LOCKS){
		printf("Process %d Thread %d DestroyLock_Syscall: lockId %d out of range\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		return;
	}
	//Check if the lock has been deleted
	kernelLockTableLock->Acquire();
	if(kernelLockTable.locks[lockId].isDeleted){
		printf("Process %d Thread %d DestroyLock_Syscall: Invalid Destroy Lock Call. lockId %d has already been deleted\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}
	//Check if the lock was created in the first place
	if(kernelLockTable.locks[lockId].lock==NULL){
		printf("Process %d Thread %d DestroyLock_Syscall: Invalid Destroy Lock call. lockId %d was not created at all\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}
	//Check if lock belongs to the current thread
	if(kernelLockTable.locks[lockId].addrSpace!=currentThread->space){
		printf("Process %d Thread %d DestroyLock_Syscall: Illegal Destroy Lock Call. lockId %d does not belong to the current thread\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}
	//If the code reached here, then the destroy lock call is a valid one
	kernelLockTable.locks[lockId].isToBeDeleted = true;
	if(kernelLockTable.locks[lockId].lockCounter>0){//is the lock in usage
		printf("Process %d Thread %d DestroyLock_Syscall: lockId %d cannot be deleted now. It is in usage\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}
	//It is ok now to destroy the lock;
	kernelLockTable.lockBitMap->Clear(lockId);//Clear the bit in the BitMap vector
	DEBUG('q',"Process %d Thread %d DestroyLock_Syscall: lockId %d and name %s has been destroyed\n", \
			currentThread->space->processId, currentThread->threadId, lockId, kernelLockTable.locks[lockId].lock->getName());
	kernelLockTable.locks[lockId].isDeleted=true;
	kernelLockTable.locks[lockId].isToBeDeleted = false;
	delete kernelLockTable.locks[lockId].lock;//Call the Lock Destructor
	kernelLockTable.locks[lockId].lock=NULL;
	kernelLockTable.locks[lockId].addrSpace==NULL;
	kernelLockTable.locks[lockId].lockCounter=0;
	kernelLockTableLock->Release();
	return;
#endif
}

/* Create Condition system call */
int CreateCondition_Syscall(unsigned int vaddr, int len)
{
#ifdef NETWORK
	char *buf;
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//Check if length is within range
	if(len<1 || len>MAX_NAME_LENGTH){
		printf("Client CreateCondition_Syscall: Illegal CV name length\n");
		delete[] buf;
		return -1;
	}

	buf = new char[len+1];
	if(buf==NULL){
		printf("Client CreateCondition_Syscall: Temp buffer cannot be created\n");
		return -1;
	}

	//Check if the passed vaddr is valid
	if(vaddr<0 || (vaddr+len)>=(currentThread->space)->addrSpaceSize){
		printf("Client CreateCondition_Syscall: Illegal vaddr passed\n");
		return -1;
	}

	//copy the name of CV from user memory to temp buffer
	if(copyin(vaddr, len, buf)==-1){//bad virtual address if the function returns -1
		printf("Client CreateCondition_Syscall: Bad Virtual address\n");
		delete[] buf;

		return -1;
	}
	buf[len]='\0';
	//data to be sent across the network
	char *data = new char[len+6];
	sprintf(data,"%d %s",CreateCondition_id, buf);
	DEBUG('p', "Client %d CreateCondition_Syscall: \"CreateCondition\" request sent to server for CV %s\n",postOffice->netAddr, buf);
	delete[] buf;
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d CreateCondition_Syscall: Negative Reply from Server. CV not created by server \n",postOffice->netAddr);
	}
	else{
		DEBUG('p', "Client %d CreateCondition_Syscall: Positive Reply from Server. CV successfully created with id %d\n",postOffice->netAddr, ret);
	}
	return ret;

#else
	int cvId;
	char *buf;

	//Check if length is within range
	if(len<1 || len>MAX_NAME_LENGTH){
		printf("Process %d Thread %d CreateCondition_Syscall: Illegal CV name length\n", \
				currentThread->space->processId, currentThread->threadId);
		delete[] buf;
		return -1;
	}

	buf = new char[len+1];
	if(buf==NULL){
		printf("Process %d Thread %d CreateCondition_Syscall: Temp buffer cannot be created\n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	//Check if the passed vaddr is valid
	if(vaddr<0 || (vaddr+len)>=(currentThread->space)->addrSpaceSize){
		printf("Process %d Thread %d CreateCondition_Syscall: Illegal vaddr passed\n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	//copy the name of CV from user memory to temp buffer
	if(copyin(vaddr, len, buf)==-1){//bad virtual address if the function returns -1
		printf("Process %d Thread %d CreateCondition_Syscall: Bad Virtual address\n", \
				currentThread->space->processId, currentThread->threadId);
		delete[] buf;

		return -1;
	}
	buf[len]='\0';

	//Check if there is room to create another CV
	kernelCVTableLock->Acquire();
	if((cvId=kernelCVTable.cvBitMap->Find()) == -1){
		printf("Process %d Thread %d CreateCondition_Syscall: Number of CV's exceeded limit\n", \
				currentThread->space->processId, currentThread->threadId);
		delete[] buf;
		kernelCVTableLock->Release();
		return -1;
	}

	//Create CV
	kernelCVTable.cvs[cvId].cv = new Condition(buf);
	DEBUG('r', "Process %d Thread %d CreateCondition_Syscall: CV with id %d and name %s has been created\n", \
			currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
	kernelCVTable.cvs[cvId].addrSpace = currentThread->space;
	kernelCVTable.cvs[cvId].isDeleted = false;
	kernelCVTable.cvs[cvId].isToBeDeleted = false;
	kernelCVTable.cvs[cvId].cvCounter = 0;
	kernelCVTableLock->Release();
	//return index of the CV table
	return(cvId);
#endif
}

/* Destroy Condition System Call*/
void DestroyCondition_Syscall(int cvId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",DestroyCondition_id, cvId);
	DEBUG('p', "Client %d DestroyCondition_Syscall: \"DestroyCondition\" request sent to server for CV id %d\n",postOffice->netAddr, cvId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d DestroyCondition_Syscall: Negative Reply from Server. CV id %d not deleted\n",postOffice->netAddr, cvId);
	}
	else{
		DEBUG('p', "Client %d DestroyCondition_Syscall: Positive Reply from Server. CV id %d successfully deleted\n",postOffice->netAddr, cvId);
	}
	return ;

#else
	//check if cvId is in a valid range
	if(cvId<0 || cvId>=MAX_CVS){
		printf("Process %d Thread %d DestroyCondition_Syscall: cvId %d out of range\n", \
				currentThread->space->processId, currentThread->threadId, cvId);
		return;
	}
	//Check if the cv has been deleted
	kernelCVTableLock->Acquire();
	if(kernelCVTable.cvs[cvId].isDeleted){
		printf("Process %d Thread %d DestroyCondition_Syscall: Invalid Destroy Condition Call. cvId %d has already been deleted\n", \
				currentThread->space->processId, currentThread->threadId, cvId);
		kernelCVTableLock->Release();
		return;
	}
	//Check if the cv was created in the first place
	if(kernelCVTable.cvs[cvId].cv==NULL){
		printf("Process %d Thread %d DestroyCondition_Syscall: Invalid Destroy Condition call. cvId %d was not created at all\n", \
				currentThread->space->processId, currentThread->threadId, cvId);
		kernelCVTableLock->Release();
		return;
	}
	//Check if cv belongs to the current thread
	if(kernelCVTable.cvs[cvId].addrSpace!=currentThread->space){
		printf("Process %d Thread %d DestroyCondition_Syscall: Illegal Destroy Condition Call. cvId %d does not belong to the current thread\n", \
				currentThread->space->processId, currentThread->threadId, cvId);
		kernelCVTableLock->Release();
		return;
	}
	//If the code reached here, then the destroy Condition call is a valid one
	kernelCVTable.cvs[cvId].isToBeDeleted = true;
	if(kernelCVTable.cvs[cvId].cvCounter>0){//is the CV in usage
		printf("Process %d Thread %d DestroyCondition_Syscall: cvId %d cannot deleted now. It is in usage\n", \
				currentThread->space->processId, currentThread->threadId,cvId);
		kernelCVTableLock->Release();
		return;
	}
	//It is ok now to destroy the cv;
	kernelCVTable.cvBitMap->Clear(cvId);//Clear the bit in the BitMap vector
	DEBUG('q',"Process %d Thread %d DestroyCondition_Syscall: cvId %d and name %s has been destroyed\n", \
			currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
	kernelCVTable.cvs[cvId].isDeleted=true;
	kernelCVTable.cvs[cvId].isToBeDeleted = false;
	delete kernelCVTable.cvs[cvId].cv;//Call the Condition Destructor
	kernelCVTable.cvs[cvId].cv=NULL;
	kernelCVTable.cvs[cvId].addrSpace==NULL;
	kernelCVTable.cvs[cvId].cvCounter=0;
	kernelCVTableLock->Release();
	return;
#endif
}


/**
 * This call would perform Acquire System Call for lock acquire.
 * performs the following checks:
 * 	- The lockId passed is a valid index
 * 	- Ensures that the lock exists
 * 	- Ensures that the lock being acquired is from the currentThread's address-space or not
 *
 * If All the checks are passed then the lock is acquired
 */
void Acquire_Syscall(int lockId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",Acquire_id, lockId);
	DEBUG('p', "Client %d Acquire_Syscall: \"Acquire\" request sent to server for lock id %d\n",postOffice->netAddr, lockId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d Acquire_Syscall: Negative Reply from Server. Lock id %d not acquired\n",postOffice->netAddr, lockId);
	}
	else{
		DEBUG('p', "Client %d Acquire_Syscall: Positive Reply from Server. Lock id %d successfully acquired\n",postOffice->netAddr, lockId);
	}
	return ;

#else
	kernelLockTableLock->Acquire();

	//Ensure if the lockId passed is legal
	if(lockId<0 || lockId >= MAX_LOCKS)
	{
		printf("Process %d Thread %d Acquire_Syscall: Invalid Acquire Call. The LockId %d is invalid\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}

	//Ensure is the lock exists or not
	if(kernelLockTable.locks[lockId].lock == NULL || kernelLockTable.locks[lockId].isDeleted )
	{
		printf("Process %d Thread %d Acquire_Syscall: The LockId %d does not exist anymore\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}

	//ensure if the lock is in the valid address-space or not
	if(kernelLockTable.locks[lockId].addrSpace!= currentThread->space)
	{
		printf("Process %d Thread %d Acquire_Syscall: address-space mismatch \n", \
				currentThread->space->processId, currentThread->threadId);
		kernelLockTableLock->Release();
		return;
	}

	//If i am here, all the conditions have been met and proceed with acquiring the lock
	//Increment the lock counter if the current thread doesn't own the lock
	if(!(kernelLockTable.locks[lockId].lock->isHeldByCurrentThread())){
		kernelLockTable.locks[lockId].lockCounter++;
	}
	kernelLockTableLock->Release();								//Release lock
	DEBUG('g', "Process %d Thread %d Acquire_Syscall: LockId %d and name %s is going to be acquired \n", \
			currentThread->space->processId, currentThread->threadId, lockId, kernelLockTable.locks[lockId].lock->getName());
	kernelLockTable.locks[lockId].lock->Acquire();				//The actual acquire call.
	DEBUG('p', "Process %d Thread %d Acquire_Syscall: LockId %d and name %s has been acquired \n", \
			currentThread->space->processId, currentThread->threadId, lockId, kernelLockTable.locks[lockId].lock->getName());

	return;
#endif
}

/**
 * This call would handle the Lock Release System Call
 * performs the following checks:
 * 	- The lockId passed is a valid index
 * 	- Ensures that the lock exists
 * 	- Ensures that the lock being acquired is from the currentThread's address-space or not
 * 	- Ensure if no other thread is waiting on this lock , before releasing it
 *
 * 	If all the checks are passed then the lock is released
 */
void Release_Syscall(int lockId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",Release_id, lockId);
	DEBUG('p', "Client %d Release_Syscall: \"Release\" request sent to server for lock id %d\n",postOffice->netAddr, lockId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d Release_Syscall: Negative Reply from Server. Lock id %d not released\n",postOffice->netAddr, lockId);
	}
	else{
		DEBUG('p', "Client %d Release_Syscall: Positive Reply from Server. Lock id %d successfully released\n",postOffice->netAddr, lockId);
	}
	return ;

#else
	kernelLockTableLock->Acquire();

	//Ensure if the lockId passed is legal
	if(lockId<0 || lockId >=MAX_LOCKS)
	{
		printf("Process %d Thread %d Release_Syscall: The LockId %d is invalid \n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}

	//Ensure is the lock exists or not
	if(kernelLockTable.locks[lockId].lock == NULL || kernelLockTable.locks[lockId].isDeleted )
	{
		printf("Process %d Thread %d Release_Syscall: The LockId %d does not exist anymore\n", \
				currentThread->space->processId, currentThread->threadId, lockId);
		kernelLockTableLock->Release();
		return;
	}

	//ensure if the lock is in the valid address-space or not
	if(kernelLockTable.locks[lockId].addrSpace!=currentThread->space)
	{
		printf("Process %d Thread %d Release_Syscall: Address-space mismatch \n", \
				currentThread->space->processId, currentThread->threadId);
		kernelLockTableLock->Release();
		return;
	}

	//Decrement the lock Counter if current thread owns the lock
	if((kernelLockTable.locks[lockId].lock->isHeldByCurrentThread())){
		kernelLockTable.locks[lockId].lockCounter--;
	}

	kernelLockTable.locks[lockId].lock->Release();		//Release call for the Kernel
	DEBUG('p', "Process %d Thread %d Release_Syscall: The LockId %d and name %s is released \n", \
			currentThread->space->processId, currentThread->threadId, lockId, kernelLockTable.locks[lockId].lock->getName());
	//Once we have released the lock; we would go on to destroy the lock if it is scheduled for deletion
	if((kernelLockTable.locks[lockId].isToBeDeleted) && (kernelLockTable.locks[lockId].lockCounter==0))
	{
		DEBUG('g', "Process %d Thread %d Release_Syscall: The LockId %d and name %s has been destroyed \n", \
				currentThread->space->processId, currentThread->threadId, lockId, kernelLockTable.locks[lockId].lock->getName());
		//destroy the lock
		kernelLockTable.lockBitMap->Clear(lockId);//Clear the bit in the BitMap vector
		kernelLockTable.locks[lockId].isDeleted=true;
		kernelLockTable.locks[lockId].isToBeDeleted = false;
		delete kernelLockTable.locks[lockId].lock;//Call the Lock Destructor
		kernelLockTable.locks[lockId].lock=NULL;
		kernelLockTable.locks[lockId].addrSpace==NULL;
		kernelLockTable.locks[lockId].lockCounter=0;
	}
	kernelLockTableLock->Release();
	return;
#endif
}




/*Yield system call*/
void Yield_Syscall()
{
	currentThread->Yield();
	return;
}

//Wait system call
void Wait_Syscall(int cvId, int lockId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d %d",Wait_id, cvId, lockId);
	DEBUG('p', "Client %d Wait_Syscall: \"Wait\" request sent to server on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	//printf("Got \"%s\" from %d, box %d\n",inBuffer,inPktHdr.from,inMailHdr.from);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d Wait_Syscall: Negative Reply from Server. Unsuccessful Wait call on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	}
	else{
		DEBUG('p', "Client %d Wait_Syscall: Positive Reply from Server. Successfully returned from wait on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	}
	return ;

#else
	//Locks are acquired here but are released in wait method in synch.cc to avoid race conditions with signal and broadcast
	kernelLockTableLock->Acquire();
	kernelCVTableLock->Acquire();
	//Check if lockId and cvId are out of bounds
	if((cvId<0) || (cvId>=MAX_CVS) || (lockId<0) || (lockId>=MAX_LOCKS) ){
		printf("Process %d Thread %d Wait_Syscall: lockId %d or cvId %d out of bounds \n", \
				currentThread->space->processId, currentThread->threadId, lockId, cvId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Check if both locks and CV's exist
	if((kernelCVTable.cvs[cvId].isDeleted==TRUE)||(kernelLockTable.locks[lockId].isDeleted==TRUE) \
			|| (kernelCVTable.cvs[cvId].cv==NULL) || (kernelLockTable.locks[lockId].lock==NULL))
	{
		printf("Process %d Thread %d Wait_Syscall: lockId %d or cvId %d do not exist\n", \
				currentThread->space->processId, currentThread->threadId, lockId, cvId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Check if cv and lock belongs to the current thread
	if((kernelCVTable.cvs[cvId].addrSpace!=currentThread->space)||(kernelLockTable.locks[lockId].addrSpace!=currentThread->space))
	{
		printf("Process %d Thread %d Wait_Syscall: Illegal Wait Condition Call. cvId %d or lockId %d does not belong to the current thread\n", \
				currentThread->space->processId, currentThread->threadId, cvId, lockId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}

	kernelCVTable.cvs[cvId].cvCounter++;
	kernelCVTableLock->Release();
	kernelLockTableLock->Release();
	//Decrement the active thread counter
	processTableLock->Acquire();
	processTable[(currentThread->space)->processId].activeThreadCntr--;
	processTableLock->Release();
	//Call the actual wait call
	DEBUG('p', "Process %d Thread %d Wait_Syscall: cvId %d and name %s is going to wait\n", \
			currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
	kernelCVTable.cvs[cvId].cv->Wait(kernelLockTable.locks[lockId].lock);
	DEBUG('g', "Process %d Thread %d Wait_Syscall: cvId %d and name %s has returned from wait\n", \
			currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
	//Increment the active thread counter
	processTableLock->Acquire();
	processTable[(currentThread->space)->processId].activeThreadCntr++;
	processTableLock->Release();
	return;
#endif
}

//Signal system call
void Signal_Syscall(int cvId, int lockId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d %d",Signal_id, cvId, lockId);
	DEBUG('p', "Client %d Signal_Syscall: \"Signal\" request sent to server on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d Signall_Syscall: Negative Reply from Server. Unsuccessful Signal call on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	}
	else{
		DEBUG('p', "Client %d Signal_Syscall: Positive Reply from Server. Successfully signaled on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	}
	return ;

#else
	kernelLockTableLock->Acquire();
	kernelCVTableLock->Acquire();
	//Check if lockId and cvId are out of bounds
	if((cvId<0) || (cvId>=MAX_CVS) || (lockId<0) || (lockId>=MAX_LOCKS) ){
		printf("Process %d Thread %d Signal_Syscall: lockId %d or cvId %d out of bounds \n", \
				currentThread->space->processId, currentThread->threadId, lockId, cvId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Check if both locks and CV's exist
	if((kernelCVTable.cvs[cvId].isDeleted==TRUE)||(kernelLockTable.locks[lockId].isDeleted==TRUE) \
			|| (kernelCVTable.cvs[cvId].cv==NULL) || (kernelLockTable.locks[lockId].lock==NULL))
	{
		printf("Process %d Thread %d Signal_Syscall: lockId %d or cvId %d do not exist\n", \
				currentThread->space->processId, currentThread->threadId, lockId, cvId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Check if cv and lock belongs to the current thread
	if((kernelCVTable.cvs[cvId].addrSpace!=currentThread->space)||(kernelLockTable.locks[lockId].addrSpace!=currentThread->space))
	{
		printf("Process %d Thread %d Signal_Syscall: Illegal Signal Condition Call. cvId %d or lockId %d does not belong to the current thread\n", \
				currentThread->space->processId, currentThread->threadId, cvId, lockId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Call the signal method of CV
	kernelCVTable.cvs[cvId].cv->Signal(kernelLockTable.locks[lockId].lock);
	DEBUG('q',"Process %d Thread %d Signal_Syscall: cvId %d and name %s has signalled\n", \
			currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
	//Decrement cv counter
	if(kernelCVTable.cvs[cvId].cvCounter>0)
	{
		kernelCVTable.cvs[cvId].cvCounter--;
	}
	//Destroy the CV if cvCounter is 0 and destroy condition has been called previously
	if(kernelCVTable.cvs[cvId].cvCounter==0 && kernelCVTable.cvs[cvId].isToBeDeleted==TRUE)
	{
		DEBUG('g', "Process %d Thread %d Signal_Syscall: cvId %d and name %s has been destroyed\n", \
				currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
		//It is ok now to destroy the cv;
		kernelCVTable.cvBitMap->Clear(cvId);//Clear the bit in the BitMap vector
		kernelCVTable.cvs[cvId].isDeleted=true;
		kernelCVTable.cvs[cvId].isToBeDeleted = false;
		delete kernelCVTable.cvs[cvId].cv;//Call the Condition Destructor
		kernelCVTable.cvs[cvId].cv=NULL;
		kernelCVTable.cvs[cvId].addrSpace==NULL;
		kernelCVTable.cvs[cvId].cvCounter=0;
	}
	kernelCVTableLock->Release();
	kernelLockTableLock->Release();	
	return;
#endif
}


//Broadcast system call
void Broadcast_Syscall(int cvId, int lockId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d %d",Broadcast_id, cvId, lockId);
	DEBUG('p', "Client %d Broadcast_Syscall: \"Broadcast\" request sent to server on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateLock message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d Broadcast_Syscall: Negative Reply from Server. Unsuccessful Broadcast call on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	}
	else{
		DEBUG('p', "Client %d Broadcast_Syscall: Positive Reply from Server. Successfully Broadcasted on CV id %d with lock id %d\n",postOffice->netAddr, cvId, lockId);
	}
	return ;

#else
	kernelLockTableLock->Acquire();
	kernelCVTableLock->Acquire();
	//Check if lockId and cvId are out of bounds
	if((cvId<0) || (cvId>=MAX_CVS) || (lockId<0) || (lockId>=MAX_LOCKS) ){
		printf("Process %d Thread %d Broadcast_Syscall: lockId %d or cvId %d out of bounds \n", \
				currentThread->space->processId, currentThread->threadId, lockId, cvId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Check if both locks and CV's exist
	if((kernelCVTable.cvs[cvId].isDeleted==TRUE)||(kernelLockTable.locks[lockId].isDeleted==TRUE) \
			|| (kernelCVTable.cvs[cvId].cv==NULL) || (kernelLockTable.locks[lockId].lock==NULL))
	{
		printf("Process %d Thread %d Broadcast_Syscall: lockId %d or cvId %d do not exist\n", \
				currentThread->space->processId, currentThread->threadId, lockId, cvId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Check if cv and lock belongs to the current thread
	if((kernelCVTable.cvs[cvId].addrSpace!=currentThread->space)||(kernelLockTable.locks[lockId].addrSpace!=currentThread->space))
	{
		printf("Process %d Thread %d Broadcast_Syscall: Illegal Signal Condition Call. cvId %d or lockId %d does not belong to the current thread\n", \
				currentThread->space->processId, currentThread->threadId, cvId, lockId);
		kernelCVTableLock->Release();
		kernelLockTableLock->Release();
		return;
	}
	//Make the counter to zero
	kernelCVTable.cvs[cvId].cvCounter=0;
	//Call the broadcast method of the CV
	kernelCVTable.cvs[cvId].cv->Broadcast(kernelLockTable.locks[lockId].lock);
	DEBUG('p', "Process %d Thread %d Broadcast_Syscall: cvId %d and name %s has broadcasted\n", \
			currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());

	//Destroy the CV if cvCounter is 0 and destroy condition has been called previously
	if(kernelCVTable.cvs[cvId].cvCounter==0 && kernelCVTable.cvs[cvId].isToBeDeleted==TRUE)
	{
		DEBUG('g', "Process %d Thread %d Broadcast_Syscall: cvId %d and name %s has been destroyed\n", \
				currentThread->space->processId, currentThread->threadId, cvId, kernelCVTable.cvs[cvId].cv->getName());
		//It is ok now to destroy the cv;
		kernelCVTable.cvBitMap->Clear(cvId);//Clear the bit in the BitMap vector
		kernelCVTable.cvs[cvId].isDeleted=true;
		kernelCVTable.cvs[cvId].isToBeDeleted = false;
		delete kernelCVTable.cvs[cvId].cv;//Call the Condition Destructor
		kernelCVTable.cvs[cvId].cv=NULL;
		kernelCVTable.cvs[cvId].addrSpace==NULL;
		kernelCVTable.cvs[cvId].cvCounter=0;
	}
	kernelCVTableLock->Release();
	kernelLockTableLock->Release();
	return;
#endif
}

//CreateMV system call
int CreateMV_Syscall(unsigned int vaddr, int len, int initValue)
{
	int ret;
#ifdef NETWORK
	char *buf;
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];

	//Check if length is within range
	if(len<1 || len>MAX_NAME_LENGTH){
		printf("Client CreateMV_Syscall: Illegal MV name length\n");

		delete[] buf;
		return -1;
	}

	buf = new char[len+1];
	if(buf==NULL){
		printf("Client CreateMV_Syscall: Temp buffer cannot be created\n");
		return -1;
	}

	//Check if the passed vaddr is valid
	if(vaddr<0 || (vaddr+len)>=(currentThread->space)->addrSpaceSize){
		printf("Client CreateMV_Syscall: Invalid virtual address passed\n");
		return -1;
	}

	//copy the name of MV from user memory to temp buffer
	if(copyin(vaddr, len, buf)==-1){//bad virtual address if the function returns -1
		printf("Client CreateMV_Syscall: Bad Virtual address\n");
		delete[] buf;
		return -1;
	}
	buf[len]='\0';

	//data to be sent across the network
	char *data = new char[len+10];
	sprintf(data,"%d %d %s",CreateMV_id, initValue, buf);
	DEBUG('p', "Client %d CreateMV_Syscall: \"CreateMV\" request sent to server for MV %s of initValue %d\n",postOffice->netAddr, buf, initValue);
	delete[] buf;
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the CreateMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p',"Client %d CreateMV_Syscall: Negative reply from Server. MV not created\n",postOffice->netAddr);
	}
	else{
		DEBUG('p',"Client %d CreateMV_Syscall: Positive reply from Server. MV successfully created with id \n",postOffice->netAddr, ret);
	}
#endif
	return ret;
}

/*DestroyMV system call*/
void DestroyMV_Syscall(int mvId)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",DestroyMV_id, mvId);
	DEBUG('p', "Client %d DestroyMV_Syscall: \"DestroyMV\" request sent to server for lock id %d\n",postOffice->netAddr, mvId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the DestroyMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d DestroyMV_Syscall: Negative Reply from Server. MV id %d not deleted\n",postOffice->netAddr, mvId);
	}
	else{
		DEBUG('p', "Client %d DestroyMV_Syscall: Positive Reply from Server. MV id %d successfully deleted\n",postOffice->netAddr, mvId);
	}
	return ;
#endif
}

/*GetMV system call */
int GetMV_Syscall(int mvId)
{
	int ret;
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];


	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",GetMV_id, mvId);
	DEBUG('p', "Client %d GetMV_Syscall: \"GetMV\" request sent to server for MV id %d\n",postOffice->netAddr, mvId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the GetMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d GetMV_Syscall: Negative Reply from Server. Unsuccessful GetMV call\n",postOffice->netAddr);
	}
	else{
		DEBUG('p', "Client %d GetMV_Syscall: Positive Reply from Server. The value of MV id %d is %d\n",\
				postOffice->netAddr, mvId, ret);
	}
#endif
	return ret;

}

/*SetMV system call*/
void SetMV_Syscall(int mvId, int setValue)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d %d",SetMV_id, mvId, setValue);
	DEBUG('p', "Client %d SetMV_Syscall: \"SetMV\" request sent to server for MV id %d\n",postOffice->netAddr, mvId);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the SetMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	//printf("Got \"%s\" from %d, box %d\n",inBuffer,inPktHdr.from,inMailHdr.from);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d SetMV_Syscall: Negative Reply from Server. Unsuccessful SetMV call\n",postOffice->netAddr);
	}
	else{
		DEBUG('p', "Client %d SetMV_Syscall: Positive Reply from Server. The value of MV id %d set to %d\n",\
				postOffice->netAddr, mvId, setValue);
	}
	return ;
#endif
}

/*Print system call*/
void Print_Syscall(unsigned int vaddr)
{
	char printBuf[MAX_CHAR_PRINTF];
	if(copyin(vaddr, MAX_CHAR_PRINTF - 1 , printBuf)==-1){
		printf("%s: Bad Virtual address\n",currentThread->getName());
		return;
	}
	printf(printBuf);
}

/*Print1 system call. It can take 1 argument*/
void Print1_Syscall(unsigned int vaddr,int arg1)
{
	char printBuf[MAX_CHAR_PRINTF];
	if(copyin(vaddr, MAX_CHAR_PRINTF - 1 , printBuf)==-1){
		printf("%s: Bad Virtual address\n",currentThread->getName());
		return;
	}
	printf(printBuf, arg1);
}

/*Print2 system call. It can take 2 arguments*/
void Print2_Syscall(unsigned int vaddr, int arg1, int arg2)
{
	char printBuf[MAX_CHAR_PRINTF];
	if(copyin(vaddr, MAX_CHAR_PRINTF - 1 , printBuf)==-1){
		printf("%s: Bad Virtual address\n",currentThread->getName());
		return;
	}
	printf(printBuf, arg1, arg2);
}

/*Print3 system call. It can take 3 argument*/
void Print3_Syscall(unsigned int vaddr, int arg1, int arg2, int arg3)
{
	char printBuf[MAX_CHAR_PRINTF];
	if(copyin(vaddr, MAX_CHAR_PRINTF - 1 , printBuf)==-1){
		printf("%s: Bad Virtual address\n",currentThread->getName());
		return;
	}
	printf(printBuf, arg1, arg2, arg3);

}


//Scanf system call. It can get only 1 input
int Scan_Syscall()
{
	int returnScanVal;
	scanf("%d", &returnScanVal);
	return returnScanVal;
}


//GetRand system call
int GetRand_Syscall()
{
	int returnScanVal;
	returnScanVal=(int)rand();
	return returnScanVal;
}


//kernel thread to start a user thread
void startUserThread(unsigned int vaddr)
{
	int i;

	// Initial program counter -- must be location of "Start"
	machine->WriteRegister(PCReg, vaddr);

	// Need to also tell MIPS where next instruction is, because
	// of branch delay possibility
	machine->WriteRegister(NextPCReg, vaddr+4);
	// Set the stackReg for the new thread that is forked.
	machine->WriteRegister(StackReg, (currentThread->stackRegVPage )* PageSize - 16);
	DEBUG('a', "All reg set for new forked thread.\n");
	(currentThread->space)->RestoreState();
	machine->Run();
	ASSERT(false);
}

void Fork_Syscall(unsigned int vaddr)
{
	//Check if the passed vaddr is valid
	if(vaddr<0 || vaddr>=(currentThread->space)->codeSize){
		printf("Process %d Thread %d Fork_Syscall: Invalid function pointer passed \n", \
				currentThread->space->processId, currentThread->threadId);
		return;
	}
	int count;
	int phyMemIndex;
	//Acquire the process table lock here to avoid race condition with exit
	processTableLock->Acquire();
	(currentThread->space)->pageTableLock->Acquire();
	// local copy of the numpages for the current addr space.
	int currentNumPages= (currentThread->space)->numPages;
	// generating a temporary pagetable with 8 pages extra.
	TranslationEntry *tempPageTable=new TranslationEntry[currentNumPages+8];
	TranslationEntry *tempPTForDeletion;
	//copying the existing pagetable data into the new pagetable.
	for(count=0;count<currentNumPages;count++)
	{
		tempPageTable[count].virtualPage=(currentThread->space)->pageTable[count].virtualPage;
		tempPageTable[count].physicalPage=(currentThread->space)->pageTable[count].physicalPage;
		tempPageTable[count].valid=(currentThread->space)->pageTable[count].valid;
		tempPageTable[count].use=(currentThread->space)->pageTable[count].use;
		tempPageTable[count].dirty=(currentThread->space)->pageTable[count].dirty;
		tempPageTable[count].readOnly=(currentThread->space)->pageTable[count].readOnly;
	}

	// Acquire the phyBitMapLock to make the fork sys call atomic.
	phyBitMapLock->Acquire();

	//initializing the newly created 8 pages.
	for (count=currentNumPages;count<currentNumPages+8;count++)
	{

		// finding a phy mem map for the new 8 pages.
		if((phyMemIndex = phyBitMap->Find())==-1)
		{
			printf("Process %d Thread %d Fork_Syscall: Fork Call had faulty termination as it could not find enough pages in physical memory\n", \
					currentThread->space->processId, currentThread->threadId);
			//TODO - This might have to be changed for the Assignment # 3
			// We might have to add the code module for the on-demand additional page
			phyBitMapLock->Release();
			interrupt->Halt();
		}

		tempPageTable[count].virtualPage=count;
		tempPageTable[count].physicalPage=phyMemIndex;
		tempPageTable[count].valid=TRUE;
		tempPageTable[count].use=FALSE;
		tempPageTable[count].dirty=FALSE;
		tempPageTable[count].readOnly=FALSE;

	}

	phyBitMapLock->Release();

	//Increase the value of numpages by 8 and update the value.
	currentNumPages=currentNumPages+8;
	(currentThread->space)->numPages = currentNumPages;
	(currentThread->space)->addrSpaceSize = (currentThread->space)->numPages * PageSize;//Change the size of the address space
	// reset the pagetable pointer ref to the new pagetable.
	tempPTForDeletion= (currentThread->space)->pageTable;
	(currentThread->space)->pageTable=tempPageTable;
	delete[] tempPTForDeletion;
	// Above Block sequence should not interchange for avoiding race condition.

	(currentThread->space)->RestoreState();

	// Create a new thread obj for the new thread to be forked.
	Thread *newForkedThread = new Thread("newForkedThread");
	// as the new thread share the same addr space.. set the new addr space to that of parent thread.
	newForkedThread->space= currentThread->space;
	newForkedThread->stackRegVPage = (newForkedThread->space)->numPages;

	(currentThread->space)->pageTableLock->Release();


	// Set the values in the process table as soon as the new thread is forked.

	//setting the threadId of the newFork Thread.
	newForkedThread->threadId=processTable[(currentThread->space)->processId].threadCntr;
	DEBUG('g', "Process %d Thread %d Fork_Syscall: A new thread with threadId %d has been forked \n", \
			currentThread->space->processId, currentThread->threadId, newForkedThread->threadId);
	// Increasing the values of the process table as necessary
	processTable[(currentThread->space)->processId].threadCntr+=1;
	processTable[(currentThread->space)->processId].activeThreadCntr+=1;
	processTable[(currentThread->space)->processId].totalThreads+=1;
	//releasing the processTableLock
	processTableLock->Release();


	newForkedThread->Fork((VoidFunctionPtr)startUserThread,vaddr);
	return;
}

//Thread to start a user process
void startUserProcess(unsigned int vaddr)
{
	currentThread->space->InitRegisters();		// set the initial register values
	currentThread->space->RestoreState();		// load page table register

	machine->Run();			// jump to the user progam
	ASSERT(FALSE);			// machine->Run never returns;
}

//Exec system call
SpaceId Exec_Syscall(unsigned int vaddr, int len)
{
	char *execBuf;

	//Check if length is within range
	if(len<1 || len>MAX_PRS_NM_LEN){
		printf("Process %d Thread %d Exec_Syscall: Illegal executable file name length \n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	execBuf = new char[len+1];

	if(execBuf==NULL){
		printf("Process %d Thread %d Exec_Syscall: Temp buffer cannot be created \n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	//Check if the passed vaddr is valid
	if(vaddr<0 || (vaddr+len)>=(currentThread->space)->addrSpaceSize){
		printf("Process %d Thread %d Exec_Syscall: Invalid function pointer \n", \
				currentThread->space->processId, currentThread->threadId);
		return -1;
	}

	//copy the name of executable from user memory to temp buffer
	if(copyin(vaddr, len, execBuf)==-1){//bad virtual address if the function returns -1
		printf("Process %d Thread %d Exec_Syscall: Bad Virtual address\n", \
				currentThread->space->processId, currentThread->threadId);
		delete[] execBuf;
		return -1;
	}
	execBuf[len]='\0';


	OpenFile *executable = fileSystem->Open(execBuf);
	AddrSpace *space;
	//If executable is null then the file sent by user does not exist
	if (executable == NULL) {
		printf("Process %d Thread %d Exec_Syscall: Unable to open file %s\n", \
				currentThread->space->processId, currentThread->threadId, execBuf);
		return 0;
	}
	//Create new thread for new process.
	Thread *firstThreadUserProcess= new Thread("firstThreadUserProcess");   
	firstThreadUserProcess->space = new AddrSpace(executable);

#ifdef NETWORK
	firstThreadUserProcess->space->mailBoxId = mailBoxCounter;
	mailBoxCounter++;
#endif

	firstThreadUserProcess->threadId=0;
	//Set the StackRegVPage for the newly created process. This is required or segmentation fault occurs in Exit syscall
	firstThreadUserProcess->stackRegVPage = (firstThreadUserProcess->space)->numPages;
	delete executable;			// close file

	DEBUG('q',"Process %d Thread %d Exec_Syscall: New process with processId %d has been created\n", \
			currentThread->space->processId, currentThread->threadId, firstThreadUserProcess->space->processId);
	//fork the new process
	firstThreadUserProcess->Fork((VoidFunctionPtr)startUserProcess,vaddr);
	return 0;
}





//Exit system call
void Exit_Syscall(int status)
{
	int PhyPageToClear,j;
	unsigned int i;

	processTableLock->Acquire();
	//if the exiting thread is the last thread or last executing thread of the last process.

	if((processTableBitMap->NumClear()==(MAX_PROCESS-1)) && \
			(((processTable[(currentThread->space)->processId].totalThreads)==1) || \
					((processTable[(currentThread->space)->processId].activeThreadCntr)==1)))
	{
		printf("Process %d Thread %d Exit_Syscall: Last thread of last process exiting ..BYE BYE Nachos!!!!\n", \
				currentThread->space->processId, currentThread->threadId);
		//halting nachos
		interrupt->Halt();
	}
	//if exiting thread is last thread or the last executing thread, but not of the last process..
	if(((processTable[(currentThread->space)->processId].totalThreads)==1) || \
			((processTable[(currentThread->space)->processId].activeThreadCntr)==1))
	{
		AddrSpace *oldAddrSpace = currentThread->space;//Variable to hold the address space to delete locks and Cv's
		//associated with the process
		//acquire the pagetable lock for the exiting thread.
		(currentThread->space)->pageTableLock->Acquire();
		phyBitMapLock->Acquire();
		//clearing all the physical pages corrosponding to the VPages in current addrspace
		for(i=0;i<(currentThread->space)->numPages;i++)
		{
			PhyPageToClear=(currentThread->space)->pageTable[i].physicalPage;
			phyBitMap->Clear(PhyPageToClear);
		}
		phyBitMapLock->Release();
		//deleting the entry for process from process bitmap...
		processTableBitMap->Clear((currentThread->space)->processId);

		(currentThread->space)->pageTableLock->Release();
		//deleting the addrspace of the exiting thread
		delete currentThread->space;
		DEBUG('q',"Process %d Thread %d Exit_Syscall: Last thread of the current process exited. Memory, Locks and CV's occupied by this process have been deleted \n", \
				currentThread->space->processId, currentThread->threadId);
		processTableLock->Release();
		//Delete all the locks associated with this process
		kernelLockTableLock->Acquire();
		for(int lockId=0; lockId<MAX_LOCKS; lockId++){
			if((kernelLockTable.lockBitMap->Test(lockId)) && \
					(kernelLockTable.locks[lockId].addrSpace==oldAddrSpace)){//if this lock is created originally
				//by the current process
				kernelLockTable.lockBitMap->Clear(lockId);//Clear the bit in the BitMap vector
				kernelLockTable.locks[lockId].isDeleted=false;
				kernelLockTable.locks[lockId].isToBeDeleted = false;
				delete kernelLockTable.locks[lockId].lock;//Call the Lock Destructor
				kernelLockTable.locks[lockId].lock=NULL;
				kernelLockTable.locks[lockId].addrSpace==NULL;
				kernelLockTable.locks[lockId].lockCounter=0;
			}
		}
		kernelLockTableLock->Release();
		//Delete all the Condition Variables associated with this process
		kernelCVTableLock->Acquire();
		for(int cvId=0; cvId<MAX_CVS; cvId++){
			if((kernelCVTable.cvBitMap->Test(cvId)) && \
					(kernelCVTable.cvs[cvId].addrSpace==oldAddrSpace)) {//if this lock is created originally
				//by the current process
				kernelCVTable.cvBitMap->Clear(cvId);//Clear the bit in the BitMap vector
				kernelCVTable.cvs[cvId].isDeleted=false;
				kernelCVTable.cvs[cvId].isToBeDeleted = false;
				delete kernelCVTable.cvs[cvId].cv;//Call the Condition Destructor
				kernelCVTable.cvs[cvId].cv=NULL;
				kernelCVTable.cvs[cvId].addrSpace==NULL;
				kernelCVTable.cvs[cvId].cvCounter=0;
			}
		}
		kernelCVTableLock->Release();
		//delete the thread
		currentThread->Finish();
	}
	else //the exiting thread is not the last thread of the current process..
	{
		(currentThread->space)->pageTableLock->Acquire();

		//Decrement the active thread and no of thread count for this process
		processTable[(currentThread->space)->processId].activeThreadCntr--;
		processTable[(currentThread->space)->processId].totalThreads--;

		phyBitMapLock->Acquire();

		//clearing the physical pages corrosponding to the stack pages of the exiting thread.
		for(j=(currentThread->stackRegVPage)-8;j<(currentThread->stackRegVPage);j++)
		{

			PhyPageToClear=(currentThread->space)->pageTable[j].physicalPage;
			//Clear only if the page is valid page on physical mem...
			//EXTENSION KEPT FOR PROJ 3 AS INSTRUCTED BY PROF. CROWLEY
			if((currentThread->space)->pageTable[j].valid)
			{
				phyBitMap->Clear(PhyPageToClear);
				(currentThread->space)->pageTable[j].valid=FALSE;
			}
		}

		phyBitMapLock->Release();
		(currentThread->space)->pageTableLock->Release();
		DEBUG('g',"Process %d Thread %d Exit_Syscall: Exited. Stack for this thread has been deleted\n", \
				currentThread->space->processId, currentThread->threadId);
		processTableLock->Release();
		//Finishing the thread that has to exit.
		currentThread->Finish();
	}
}



//system call to append to a list
void ListAppend_Syscall(int item)
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d %d",ListAppend_id, item);
	DEBUG('p', "Client %d ListAppend_Syscall: \"ListAppend\" request sent to server for item %d\n",postOffice->netAddr,item);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the GetMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d ListAppend_Syscall: Negative Reply from Server. Unsuccessful ListAppend call\n",postOffice->netAddr);
	}
	else{
		DEBUG('p', "Client %d ListAppend_Syscall: Positive Reply from Server. Successful ListAppend call\n",\
				postOffice->netAddr);
	}
	return;
#else
	int *restockItem = new int(item);
	(currentThread->space)->reStockList_kernel.Append((void *)restockItem);
#endif
}

//system call to remove item from a list
int ListRemove_Syscall()
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d",ListRemove_id);
	DEBUG('p', "Client %d ListRemove_Syscall: \"ListRemove\" request sent to server \n",postOffice->netAddr);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the GetMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d ListRemove_Syscall: Negative Reply from Server. Unsuccessful ListRemove call\n",postOffice->netAddr);
	}
	else{
		DEBUG('p', "Client %d ListRemove_Syscall: Positive Reply from Server. Successful ListRemove call with item %d\n",\
				postOffice->netAddr, ret);
	}
	return ret;
#else

	int myaisle;
	int *restockItem = (int *)(currentThread->space)->reStockList_kernel.Remove();
	myaisle =*restockItem;
	delete restockItem;
	return myaisle;
#endif
}

//system call to check if the list is empty
int IsListEmpty_Syscall()
{
#ifdef NETWORK
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	char inBuffer[MaxMailSize];
	int ret;

	//data to be sent across the network
	char *data = new char[MaxMailSize];
	sprintf(data,"%d",IsListEmpty_id);
	DEBUG('p', "Client %d IsListEmpty_Syscall: \"IsListEmpty\" request sent to server \n",postOffice->netAddr);
	if(proj4part1){
		outPktHdr.to = ServerMachineId;
	}
	else{
		outPktHdr.to = rand() % noOfServers;
	}
	outMailHdr.to = ServerMailBoxId;
	outMailHdr.from = currentThread->space->mailBoxId;
	outMailHdr.length = strlen(data) + 1;

	// Send the GetMV message to the server
	bool success = postOffice->Send(outPktHdr, outMailHdr, data);
	delete[] data;
	if ( !success ) {
		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
		interrupt->Halt();
	}

	//Wait for the reply from server
	postOffice->Receive(currentThread->space->mailBoxId, &inPktHdr, &inMailHdr, inBuffer);
	fflush(stdout);
	ret=atoi(inBuffer);
	if(ret==-1){
		DEBUG('p', "Client %d IsListEmpty_Syscall: Negative Reply from Server. Unsuccessful IsListEmpty call\n",postOffice->netAddr);
	}
	else{
		DEBUG('p', "Client %d IsListEmpty_Syscall: Positive Reply from Server. Successful IsListEmpty call with return value %d\n",\
				postOffice->netAddr, ret);
	}
	return ret;
#else

	return((currentThread->space)->reStockList_kernel.IsEmpty());
#endif
}



void ExceptionHandler(ExceptionType which) {
	int type = machine->ReadRegister(2); // Which syscall?
	int rv=0; 	// the return value from a syscall

	if ( which == SyscallException ) {
		switch (type) {
		default:
			DEBUG('a', "Unknown syscall - shutting down.\n");
		case SC_Halt:
			DEBUG('a', "Shutdown, initiated by user program.\n");
			interrupt->Halt();
			break;
		case SC_Create:
			DEBUG('a', "Create syscall.\n");
			Create_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
			break;
		case SC_Open:
			DEBUG('a', "Open syscall.\n");
			rv = Open_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
			break;
		case SC_Write:
			DEBUG('a', "Write syscall.\n");
			Write_Syscall(machine->ReadRegister(4),
					machine->ReadRegister(5),
					machine->ReadRegister(6));
			break;
		case SC_Read:
			DEBUG('a', "Read syscall.\n");
			rv = Read_Syscall(machine->ReadRegister(4),
					machine->ReadRegister(5),
					machine->ReadRegister(6));
			break;
		case SC_Close:
			DEBUG('a', "Close syscall.\n");
			Close_Syscall(machine->ReadRegister(4));
			break;

		case SC_Yield:
			DEBUG('a', "Yield syscall.\n");
			Yield_Syscall();
			break;

		case SC_CreateLock:
			DEBUG('a', "Create Lock syscall.\n");
			rv = CreateLock_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
			break;

		case SC_DestroyLock:
			DEBUG('a', "Destroy Lock syscall.\n");
			DestroyLock_Syscall(machine->ReadRegister(4));
			break;

		case SC_CreateCondition:
			DEBUG('a', "Create Condition syscall.\n");
			rv = CreateCondition_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
			break;

		case SC_DestroyCondition:
			DEBUG('a', "Destroy Condition syscall.\n");
			DestroyCondition_Syscall(machine->ReadRegister(4));
			break;

		case SC_Wait:
			DEBUG('a',"Wait System Call.\n");
			Wait_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
			break;

		case SC_Signal:
			DEBUG('a',"Signal System Call.\n");
			Signal_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
			break;

		case SC_Broadcast:
			DEBUG('a',"Broadcast System Call.\n");
			Broadcast_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
			break;

		case SC_Acquire:
			DEBUG('a', "Acquire Lock syscall.\n");
			Acquire_Syscall(machine->ReadRegister(4));
			break;

		case SC_Release:
			DEBUG('a', "Release Lock syscall.\n");
			Release_Syscall(machine->ReadRegister(4));
			break;

		case SC_Scan:
			DEBUG('a',"Scan System Call.\n");
			rv = Scan_Syscall();
			break;

		case SC_Print:
			DEBUG('a', "Print syscall.\n");
			Print_Syscall(machine->ReadRegister(4));
			break;

		case SC_Print1:
			DEBUG('a', "Print 1 syscall.\n");
			Print1_Syscall(machine->ReadRegister(4),machine->ReadRegister(5));
			break;

		case SC_Print2:
			DEBUG('a', "Print 2 syscall.\n");
			Print2_Syscall(machine->ReadRegister(4),machine->ReadRegister(5),machine->ReadRegister(6));
			break;

		case SC_Print3:
			DEBUG('a', "Print 3 syscall.\n");
			Print3_Syscall(machine->ReadRegister(4),machine->ReadRegister(5),machine->ReadRegister(6),machine->ReadRegister(7));
			break;

		case SC_GetRand:
			DEBUG('a', "Get Rand syscall.\n");
			rv = GetRand_Syscall();
			break;

		case SC_Fork:
			DEBUG('a',"Fork System Call.\n");
			Fork_Syscall(machine->ReadRegister(4));
			break;

		case SC_Exit:
			DEBUG('a',"Exit System Call.\n");
			Exit_Syscall(machine->ReadRegister(4));
			break;

		case SC_Exec:
			DEBUG('a',"Exec System Call.\n");
			rv = Exec_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
			break;

		case SC_ListAppend:
			DEBUG('a',"ListAppend System Call.\n");
			ListAppend_Syscall(machine->ReadRegister(4));
			break;

		case SC_ListRemove:
			DEBUG('a',"ListRemove System Call.\n");
			rv = ListRemove_Syscall();
			break;

		case SC_IsListEmpty:
			DEBUG('a',"ListRemove System Call.\n");
			rv = IsListEmpty_Syscall();
			break;

		case SC_CreateMV:
			DEBUG('a',"CreateMV System Call.\n");
			rv = CreateMV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5), machine->ReadRegister(6));
			break;

		case SC_DestroyMV:
			DEBUG('a',"DestroyMV System Call.\n");
			DestroyMV_Syscall(machine->ReadRegister(4));
			break;

		case SC_GetMV:
			DEBUG('a',"GetMV System Call.\n");
			rv = GetMV_Syscall(machine->ReadRegister(4));
			break;

		case SC_SetMV:
			DEBUG('a',"SetMV System Call.\n");
			SetMV_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
			break;
		}

		// Put in the return value and increment the PC
		machine->WriteRegister(2,rv);
		machine->WriteRegister(PrevPCReg,machine->ReadRegister(PCReg));
		machine->WriteRegister(PCReg,machine->ReadRegister(NextPCReg));
		machine->WriteRegister(NextPCReg,machine->ReadRegister(PCReg)+4);
		return;
	}
	else {
		cout<<"Unexpected user mode exception - which:"<<which<<"  type:"<< type<<endl;
		interrupt->Halt();
	}
}
